#include <osal/osal.h>
#include <basic_types.h>
#include <Mediatypes.h>	

#include <api/libc/alloc.h>
#include <api/libc/printf.h>
#include <api/libc/string.h>

#include "vbi_buffer.h"

extern struct vbi_config_par *g_vbi27_pconfig_par;
//static UINT8 vbi_bs_buf[VBI_BS_LEN];
//static UINT8* vbi_bs_end = vbi_bs_buf + VBI_BS_LEN;
static UINT8* vbi_bs_buf;
static UINT8* vbi_bs_end;

static UINT8* vbi_wr_ptr;
static UINT8* vbi_rd_ptr;

static UINT32 vbi_hdr_wr_ptr;
static UINT32 vbi_hdr_rd_ptr;

INT32 vbi_sbf_create(void)
{
	vbi_bs_buf = (UINT8 *)g_vbi27_pconfig_par->mem_map.sbf_start_addr;
	vbi_bs_end = (UINT8 *)(vbi_bs_buf + g_vbi27_pconfig_par->mem_map.sbf_size);
	vbi_wr_ptr = (UINT8 *)(vbi_bs_buf + LOOPBACK_SIZE);
	vbi_rd_ptr = (UINT8 *)(vbi_bs_buf + LOOPBACK_SIZE);

	return RET_SUCCESS;
}
//note : buf need 1 byte remaining at least,that means full , or can not differ from empty when rd = wr
INT32 vbi_sbf_wr_req(UINT32 * pSize, UINT8 ** ppData)
{
	UINT32 remain_size;
	UINT8 *cur_wr_ptr ;
	UINT8 *cur_rd_ptr ;
	
	cur_wr_ptr = vbi_wr_ptr;
	cur_rd_ptr = vbi_rd_ptr;	
	
	SBF_ASSERT(cur_rd_ptr < vbi_bs_end && cur_wr_ptr < vbi_bs_end );
	if(cur_rd_ptr < vbi_bs_buf+LOOPBACK_SIZE && cur_wr_ptr == vbi_bs_buf+LOOPBACK_SIZE)
	{
		remain_size = 0;
	}
	else if(cur_rd_ptr <= cur_wr_ptr)
	{
		if(cur_rd_ptr != vbi_bs_buf+LOOPBACK_SIZE)
			remain_size = vbi_bs_end - cur_wr_ptr;  // remain space
		else
			remain_size = vbi_bs_end - cur_wr_ptr -1;  		
	}
	else// if(cur_rd_ptr > cur_wr_ptr)
	{
		remain_size = cur_rd_ptr - cur_wr_ptr -1;
	}

	if(remain_size == 0)
	{		
		return RET_FAILURE;
	}
	
	*pSize  = (remain_size >= *pSize)?(*pSize):remain_size;
	*ppData = cur_wr_ptr;

	return RET_SUCCESS;
}


/**************************************************************************/
void vbi_sbf_wr_update(UINT32 Size)
{
	UINT32 remain_size;
	UINT8 *cur_wr_ptr ;
	UINT8 *cur_rd_ptr ;
	
	cur_wr_ptr = vbi_wr_ptr;
	cur_rd_ptr = vbi_rd_ptr;	
	
	SBF_ASSERT(cur_rd_ptr < vbi_bs_end && cur_wr_ptr < vbi_bs_end );

	if(cur_rd_ptr < vbi_bs_buf+LOOPBACK_SIZE && cur_wr_ptr == vbi_bs_buf+LOOPBACK_SIZE)
	{
		return;//SBF_ASSERT(0);
	}	
	else if(cur_rd_ptr <= cur_wr_ptr)
	{
		if(cur_rd_ptr != vbi_bs_buf+LOOPBACK_SIZE)
			remain_size = vbi_bs_end - cur_wr_ptr;  // remain space
		else
			remain_size = vbi_bs_end - cur_wr_ptr -1;  
	}
	else// if(cur_rd_ptr > cur_wr_ptr)
	{
		remain_size = cur_rd_ptr - cur_wr_ptr -1;
	}

	SBF_ASSERT(Size<=remain_size);

	cur_wr_ptr += Size;
	if(cur_wr_ptr >= vbi_bs_end)
		cur_wr_ptr = vbi_bs_buf+LOOPBACK_SIZE;

	vbi_wr_ptr = cur_wr_ptr;
	return ;
}
/***********************************************************************/
INT32 vbi_sbf_rd_req(UINT32 * pSize, UINT8 ** ppData)
{
	UINT32 remain_size;
	UINT8 *cur_wr_ptr ;
	UINT8 *cur_rd_ptr ;
	
	cur_wr_ptr = vbi_wr_ptr;
	cur_rd_ptr = vbi_rd_ptr;	

	SBF_ASSERT(cur_rd_ptr < vbi_bs_end && cur_wr_ptr < vbi_bs_end );
	
	if(cur_rd_ptr < vbi_bs_buf+LOOPBACK_SIZE && cur_wr_ptr == vbi_bs_buf+LOOPBACK_SIZE)
	{
		remain_size = vbi_bs_end - cur_rd_ptr;
	}
	else if(cur_rd_ptr <= cur_wr_ptr)
	{
		remain_size = cur_wr_ptr - cur_rd_ptr;
	}
	else// if(cur_rd_ptr > cur_wr_ptr)
	{
		remain_size = vbi_bs_end - cur_rd_ptr;
	}

	if(remain_size == 0)
		return RET_FAILURE;	
	
	*pSize  = (remain_size >= *pSize)?(*pSize):remain_size;
	*ppData = cur_rd_ptr;

	   
	return RET_SUCCESS;
}

/************************************************************************/
void vbi_sbf_rd_update(UINT32 Size)
{
	UINT32 remain_size;
	UINT8 *cur_wr_ptr ;
	UINT8 *cur_rd_ptr ;

	cur_wr_ptr = vbi_wr_ptr;
	cur_rd_ptr = vbi_rd_ptr;	

	SBF_ASSERT(cur_rd_ptr < vbi_bs_end && cur_wr_ptr < vbi_bs_end );

	if(cur_rd_ptr < vbi_bs_buf+LOOPBACK_SIZE && cur_wr_ptr == vbi_bs_buf+LOOPBACK_SIZE)
	{
		remain_size = vbi_bs_end - cur_rd_ptr;
	}	
	else if(cur_rd_ptr <= cur_wr_ptr)
	{
		remain_size = cur_wr_ptr - cur_rd_ptr;
	}
	else// if(cur_rd_ptr > cur_wr_ptr)
	{
		remain_size = vbi_bs_end - cur_rd_ptr;
	}

	
	SBF_ASSERT(Size<=remain_size);

	cur_rd_ptr += Size;
	if(cur_rd_ptr >= vbi_bs_end)
		cur_rd_ptr = vbi_bs_buf+LOOPBACK_SIZE;

	vbi_rd_ptr = cur_rd_ptr;
	return ;
}
void vbi_sbf_loopback(UINT8* src,UINT32 size,UINT8* head_ptr)
{
	SBF_ASSERT(head_ptr == vbi_bs_buf+LOOPBACK_SIZE);
	SBF_ASSERT(size <= LOOPBACK_SIZE);
	
	MEMCPY((void*)((UINT32)head_ptr-size),(void*)src,size);
	vbi_rd_ptr = head_ptr-size;	
	return;
}

INT32 vbi_hdr_buf_create(void)
{
	vbi_hdr_wr_ptr = 0;
	vbi_hdr_rd_ptr = 0;
	return RET_SUCCESS;
}
//note : buf need 1 byte remaining at least,that means full , or can not differ from empty when rd = wr
INT32 vbi_hdr_buf_wr_req(UINT32* pData)
{
	UINT32 remain_size;
	UINT32 cur_wr_ptr ;
	UINT32 cur_rd_ptr ;
	
	cur_wr_ptr = vbi_hdr_wr_ptr;
	cur_rd_ptr = vbi_hdr_rd_ptr;	

	SBF_ASSERT(cur_rd_ptr < VBI_BS_HDR_LEN && cur_wr_ptr < VBI_BS_HDR_LEN );
	
	if(cur_rd_ptr <= cur_wr_ptr)
	{
		if(cur_rd_ptr != 0)
			remain_size = VBI_BS_HDR_LEN - cur_wr_ptr;  // remain space
		else
			remain_size = VBI_BS_HDR_LEN - cur_wr_ptr -1;  		
	}
	else// if(cur_rd_ptr > cur_wr_ptr)
	{
		remain_size = cur_rd_ptr - cur_wr_ptr -1;
	}

	if(remain_size == 0)
		return RET_FAILURE;
	
	*pData = cur_wr_ptr;
	return RET_SUCCESS;
}


/**************************************************************************/
void vbi_hdr_buf_wr_update()
{
	UINT32 remain_size;
	UINT32 cur_wr_ptr ;
	UINT32 cur_rd_ptr ;
	
	cur_wr_ptr = vbi_hdr_wr_ptr;
	cur_rd_ptr = vbi_hdr_rd_ptr;	


	SBF_ASSERT(cur_rd_ptr < VBI_BS_HDR_LEN && cur_wr_ptr < VBI_BS_HDR_LEN );

	
	if(cur_rd_ptr <= cur_wr_ptr)
	{
		if(cur_rd_ptr != 0)
			remain_size = VBI_BS_HDR_LEN - cur_wr_ptr;  // remain space
		else
			remain_size = VBI_BS_HDR_LEN - cur_wr_ptr -1;  		
	}
	else// if(cur_rd_ptr > cur_wr_ptr)
	{
		remain_size = cur_rd_ptr - cur_wr_ptr -1;
	}

	SBF_ASSERT(remain_size>=1);


	cur_wr_ptr += 1;
	if(cur_wr_ptr >= VBI_BS_HDR_LEN)
		cur_wr_ptr = 0;
	
	vbi_hdr_wr_ptr = cur_wr_ptr;

	return ;
}
/***********************************************************************/
INT32 vbi_hdr_buf_rd_req(UINT32 * pData)
{
	UINT32 remain_size;
	UINT32 cur_wr_ptr ;
	UINT32 cur_rd_ptr ;
	
	cur_wr_ptr = vbi_hdr_wr_ptr;
	cur_rd_ptr = vbi_hdr_rd_ptr;	

	//PRINTF("wr=%x,rd=%x\n",cur_wr_ptr,cur_rd_ptr);

	SBF_ASSERT(cur_rd_ptr < VBI_BS_HDR_LEN && cur_wr_ptr < VBI_BS_HDR_LEN );
	
	if(cur_rd_ptr <= cur_wr_ptr)
	{
		remain_size = cur_wr_ptr - cur_rd_ptr;
	}
	else// if(cur_rd_ptr > cur_wr_ptr)
	{
		remain_size = VBI_BS_HDR_LEN - cur_rd_ptr;
	}

	if(remain_size == 0)
		return RET_FAILURE;	

	*pData = cur_rd_ptr;
	return RET_SUCCESS;
}

/************************************************************************/
void vbi_hdr_buf_rd_update()
{
	UINT32 remain_size;
	UINT32 cur_wr_ptr ;
	UINT32 cur_rd_ptr ;
	
	cur_wr_ptr = vbi_hdr_wr_ptr;
	cur_rd_ptr = vbi_hdr_rd_ptr;	


	SBF_ASSERT(cur_rd_ptr < VBI_BS_HDR_LEN && cur_wr_ptr < VBI_BS_HDR_LEN );
	
	if(cur_rd_ptr <= cur_wr_ptr)
	{
		remain_size = cur_wr_ptr - cur_rd_ptr;
	}
	else// if(cur_rd_ptr > cur_wr_ptr)
	{
		remain_size = VBI_BS_HDR_LEN - cur_rd_ptr;
	}

	SBF_ASSERT(remain_size>=1);

	cur_rd_ptr += 1;
	if(cur_rd_ptr >= VBI_BS_HDR_LEN)
		cur_rd_ptr = 0;
	
	vbi_hdr_rd_ptr = cur_rd_ptr;

	return ;
}


static struct PBF_CB * g_pbf_cb[800];

void pbf_create()
{	
	int i;

	UINT32 size_cb = sizeof(struct PBF_CB);
	UINT32 size_unit = 1000 + size_cb;
	
	for(i=0;i<800;i++)
	{          
		g_pbf_cb[i] = (struct PBF_CB *)(g_vbi27_pconfig_par->mem_map.pbf_start_addr+ size_unit*i);
		g_pbf_cb[i]->valid = 0x00;
		g_pbf_cb[i]->page_id = 0xffff;
	    g_pbf_cb[i]->sub_page_id = 0xffff;
		g_pbf_cb[i]->buf_start = (UINT8*)(g_vbi27_pconfig_par->mem_map.pbf_start_addr + size_unit*i + size_cb);
		g_pbf_cb[i]->link_red = 0xffff;	
		g_pbf_cb[i]->link_green = 0xffff;	
		g_pbf_cb[i]->link_yellow = 0xffff;	
		g_pbf_cb[i]->link_cyan = 0xffff;	
		g_pbf_cb[i]->complement_line = 0;
         
		MEMSET(g_pbf_cb[i]->buf_start, 0x00, 1000);
	}
    
	return ;
}

INT32 pbf_wr_req(UINT16 page_id , struct PBF_CB ** cb )
{
	UINT16 cb_index;//0-799

   	if(page_id > 899 || page_id < 100)
   	{
        return RET_FAILURE;
        //cb_index = 0;
   	}
	else 
		cb_index = page_id -100;  

	*cb = g_pbf_cb[cb_index];
	//(*cb)->valid = 0x01;
	
	return RET_SUCCESS;
}

INT32 pbf_rd_req(UINT16 page_id , struct PBF_CB ** cb )
{
	UINT16 cb_index;
	
   	if(page_id > 899 || page_id < 100)
		cb_index = 0;
	else 
		cb_index = page_id -100;  
	
	if(g_pbf_cb[cb_index]->valid == 0x00)
	{
		return RET_FAILURE;			
	}
	*cb = g_pbf_cb[cb_index];

	return RET_SUCCESS;	
}


INT32 pbf_rd_req_up(UINT16 page_id , struct PBF_CB ** cb )
{

	int cnt= 0;	
	UINT16 cb_index;
   	
   	if(page_id > 899 || page_id < 100)
		cb_index = 0;
	else 
		cb_index = page_id -100;  
	
	if(cb_index == 799)
	   	cb_index = 0;
	else
		cb_index ++;
	
	while(g_pbf_cb[cb_index]->valid == 0x00)
	{
		if (cnt++ >800)
		{
			return RET_FAILURE;
		}
		if(cb_index == 799)
		   	cb_index = 0;
		else
			cb_index ++;
	}

	*cb = g_pbf_cb[cb_index];

	return RET_SUCCESS;	
}

INT32 pbf_rd_req_down(UINT16 page_id , struct PBF_CB ** cb )
{
	int cnt= 0;	
	UINT16 cb_index;

   	if(page_id > 899 || page_id < 100)
		cb_index = 0;
	else 
		cb_index = page_id -100;  
   	   	
	   
	 if(cb_index == 0)
	   	cb_index = 799;
	 else
	 	cb_index --;


	while(g_pbf_cb[cb_index]->valid == 0x00)
	{
		if (cnt++ >800)
		{
			return RET_FAILURE;
		}
		
		 if(cb_index == 0)
		   		cb_index = 799;
		 else
		 	cb_index --;
	}
	
	*cb = g_pbf_cb[cb_index];

	return RET_SUCCESS;	
}

